#include "stdafx.h"
#include "ModelManager.h"
#include "RenderSystem.h"
#include <fstream>

ModelManager::ModelManager(RenderSystem* render_system, const String& model_directory) : m_directory(model_directory), m_render_system(render_system)
{
}


ModelManager::~ModelManager(void)
{
	if (m_models.empty())
		return;

	auto it = m_models.begin();
	while (it != m_models.end())
	{
		it->second->Release();
		delete it->second;
		it->second = nullptr;
		it++;
	}
	m_models.clear();
}

Renderable* ModelManager::Create(const String& model_filename)
{
	auto it = m_models.find(model_filename);

	if (it == m_models.end())
	{
		Renderable* renderable = new Renderable;
		LoadModel(m_directory + model_filename, renderable);

		m_models.insert(std::make_pair(model_filename, renderable));
		
		it = m_models.find(model_filename);
	}

	return it->second;
}

void ModelManager::Destroy(Renderable* renderable)
{
	auto it = m_models.begin();

	while (it != m_models.end())
	{
		if (it->second == renderable)
		{
			renderable->Release();
			m_models.erase(it);
			break;
		}
		it++;
	}
}


void ModelManager::LoadModel(const String& model_filename, Renderable* renderable)
{
	struct FaceType
	{
		int vIndex1, vIndex2, vIndex3;
		int tIndex1, tIndex2, tIndex3;
		int nIndex1, nIndex2, nIndex3;
	};

	int vertexCount = 0, textureCount = 0, normalCount = 0, faceCount = 0;
	Vertex* vertices, *texcoords, *normals;
	FaceType* faces;

	std::ifstream fin;
	int vertexIndex = 0, texcoordIndex = 0, normalIndex = 0, faceIndex = 0, vIndex = 0, tIndex = 0, nIndex = 0;
	char input, input2;
	
	fin.open(model_filename);

	fin.get(input);

	while (!fin.eof())
	{
		if (input == 'v')
		{
			fin.get(input);
			if (input == ' ')
				vertexCount++;
			if (input == 't')
				textureCount++;
			if (input == 'n')
				normalCount++;
		}

		if (input == 'f')
		{
			fin.get(input);
			if (input == ' ')
				faceCount++;
		}

		while (input != '\n')
			fin.get(input);

		fin.get(input);
	}

	fin.close();


	// read in the data from file
	vertices = new Vertex[vertexCount];
	texcoords = new Vertex[textureCount];
	normals = new Vertex[normalCount];
	faces = new FaceType[faceCount];

	fin.open(model_filename);

	fin.get(input);
	while (!fin.eof())
	{
		if (input == 'v')
		{
			fin.get(input);

			if (input == ' ')
			{
				fin >> vertices[vertexIndex].position.x >> vertices[vertexIndex].position.y >> vertices[vertexIndex].position.z;

				// Invert coordinates to left hand system
				vertices[vertexIndex].position.z = vertices[vertexIndex].position.z * -1.0f;
				vertexIndex++;
			}

			if (input == 't')
			{
				fin >> texcoords[texcoordIndex].texcoord.x >> texcoords[texcoordIndex].texcoord.y;

				// Invert texture coordinates to left hand system
				texcoords[texcoordIndex].texcoord.y = 1.0f - texcoords[texcoordIndex].texcoord.y;
				texcoordIndex++;
			}
			
			if (input == 'n')
			{
				fin >> normals[normalIndex].normal.x >> normals[normalIndex].normal.y >> normals[normalIndex].normal.z;

				// Invert normal to left hand system
				normals[normalIndex].normal.y = normals[normalIndex].normal.y * -1.0f;
				normals[normalIndex].normal.z = normals[normalIndex].normal.z * -1.0f;
				normalIndex++;
			}
		}

		if (input == 'f')
		{
			fin.get(input);

			if (input == ' ')
			{
				fin >> faces[faceIndex].vIndex3 >> input2 >> faces[faceIndex].tIndex3 >> input2 >> faces[faceIndex].nIndex3
					>> faces[faceIndex].vIndex2 >> input2 >> faces[faceIndex].tIndex2 >> input2 >> faces[faceIndex].nIndex2
					>> faces[faceIndex].vIndex1 >> input2 >> faces[faceIndex].tIndex1 >> input2 >> faces[faceIndex].nIndex1;
				faceIndex++;
			}
		}

		while (input != '\n')
			fin.get(input);

		fin.get(input);
	}

	fin.close();

	Vertex* finalVerts = new Vertex[faceIndex * 3]; //vertexCount * faceCount
	unsigned int currentVertex = 0;

	for (int i = 0; i < faceIndex; i++)
	{
		vIndex = faces[i].vIndex1 - 1;
		tIndex = faces[i].tIndex1 - 1;
		nIndex = faces[i].nIndex1 - 1;

		Vertex tempVertex;

		// position
		tempVertex.position.x = vertices[vIndex].position.x;
		tempVertex.position.y = vertices[vIndex].position.y;
		tempVertex.position.z = vertices[vIndex].position.z;

		// texture coords
		tempVertex.texcoord.x = texcoords[tIndex].texcoord.x;
		tempVertex.texcoord.y = texcoords[tIndex].texcoord.y;

		// normals
		tempVertex.normal.x = normals[nIndex].normal.x;
		tempVertex.normal.y = normals[nIndex].normal.y;
		tempVertex.normal.z = normals[nIndex].normal.z;

		finalVerts[currentVertex] = tempVertex;
		currentVertex++;

		vIndex = faces[i].vIndex2 - 1;
		tIndex = faces[i].tIndex2 - 1;
		nIndex = faces[i].nIndex2 - 1;

		// position
		tempVertex.position.x = vertices[vIndex].position.x;
		tempVertex.position.y = vertices[vIndex].position.y;
		tempVertex.position.z = vertices[vIndex].position.z;

		// texture coords
		tempVertex.texcoord.x = texcoords[tIndex].texcoord.x;
		tempVertex.texcoord.y = texcoords[tIndex].texcoord.y;

		// normals
		tempVertex.normal.x = normals[nIndex].normal.x;
		tempVertex.normal.y = normals[nIndex].normal.y;
		tempVertex.normal.z = normals[nIndex].normal.z;

		finalVerts[currentVertex] = tempVertex;
		currentVertex++;

		vIndex = faces[i].vIndex3 - 1;
		tIndex = faces[i].tIndex3 - 1;
		nIndex = faces[i].nIndex3 - 1;

		// position
		tempVertex.position.x = vertices[vIndex].position.x;
		tempVertex.position.y = vertices[vIndex].position.y;
		tempVertex.position.z = vertices[vIndex].position.z;

		// texture coords
		tempVertex.texcoord.x = texcoords[tIndex].texcoord.x;
		tempVertex.texcoord.y = texcoords[tIndex].texcoord.y;

		// normals
		tempVertex.normal.x = normals[nIndex].normal.x;
		tempVertex.normal.y = normals[nIndex].normal.y;
		tempVertex.normal.z = normals[nIndex].normal.z;

		finalVerts[currentVertex] = tempVertex;
		currentVertex++;
	}


	renderable->m_count = faceIndex * 3;
	m_render_system->CreateVertexBuffer(&renderable->m_vertex_buffer,BM_DEFAULT,
		renderable->m_count,sizeof(Vertex),finalVerts);

	delete [] finalVerts;
	delete [] vertices;
	delete [] texcoords;
	delete [] normals;
	delete [] faces;
}

void ModelManager::CreatePlane(const String& id, float x, float y){

}

Renderable* ModelManager::GetModel(const String& id){
	auto it = m_models.find(id);
	if (it != m_models.end()){
		return it->second;
	}
	return nullptr;
}